package com.cqjtu.eecs.filter;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.cqjtu.eecs.entity.Permission;
import com.cqjtu.eecs.entity.Role;
import com.cqjtu.eecs.entity.User;
import com.cqjtu.eecs.exception.TokenErrorException;
import com.cqjtu.eecs.service.IUserService;
import com.cqjtu.eecs.service.impl.RedisService;
import com.cqjtu.eecs.utils.JwtUtils;
import io.jsonwebtoken.Claims;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * jwt权限过滤类
 * @author luojun
 * @since 2022-03-05
 */
@Slf4j
public class JWTAuthenticationFilter extends BasicAuthenticationFilter {
    @Autowired
    private RedisService redisService;
    @Autowired
    private IUserService userService;

    public JWTAuthenticationFilter(AuthenticationManager authenticationManager) {
        super(authenticationManager);
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request,
                                    HttpServletResponse response,
                                    FilterChain chain
    ) throws IOException, ServletException {
        // 从请求头中获取token
        String token = request.getHeader(JwtUtils.HEADER);
        // 如果token为空，则直接放行
        if (token == null || token.trim().equals("")){
            chain.doFilter(request, response);
            return;
        }
        // 验证token是否合法
        Claims claims = JwtUtils.checkToken(token);
        if (claims == null){
            log.info("token异常");
            throw new TokenErrorException("token异常");
        }
        // 检测token是否过期
        if (JwtUtils.isTokenExpired(claims)){
            log.info("token已过期");
            throw new TokenErrorException("token过期，请重新登录");
        }
        // 获取user信息
        String userName = (String)claims.get(JwtUtils.USERNAME);
        String passWord = (String)claims.get(JwtUtils.PASSWORD);
        Set<GrantedAuthority> authorities = new HashSet<>();
        // 从redis中获取对应的权限信息
        String authoritiesString = redisService.getString(userName);
        if (authoritiesString != null){ // redis中找到
            List list = JSONObject.parseObject(authoritiesString, List.class);
            for (int i = 0; i < list.size(); i++) {
                authorities.add(JSONObject.parseObject(JSONObject.toJSONString(list.get(i)) ,
                        SimpleGrantedAuthority.class));
            }
        }
        else{  // redis中未找到，去数据库中取
            User user = userService.getOne(new LambdaQueryWrapper<User>().eq(User::getUsername, userName));
            authorities = userService.listUserPermissionSet(user.getUid());
            // 在redis中缓存一份
            redisService.setEXString(user.getUsername(),
                    JSON.toJSONString(authorities),
                    Integer.toUnsignedLong(JwtUtils.EXPIRATION));
        }
        // 将信息注册进security
        UsernamePasswordAuthenticationToken info = new UsernamePasswordAuthenticationToken(userName, passWord, authorities);
        SecurityContextHolder.getContext().setAuthentication(info);
        chain.doFilter(request, response);
    }
}
